package com.huawei.esdk.oa.device.ad.common;

import java.io.IOException;
import java.net.URL;
import org.apache.directory.ldap.client.api.LdapConnection;
import org.apache.directory.ldap.client.api.LdapConnectionConfig;
import org.apache.directory.ldap.client.api.LdapConnectionPool;
import org.apache.directory.ldap.client.api.NoVerificationTrustManager;
import org.apache.directory.ldap.client.api.PoolableLdapConnectionFactory;
import org.apache.log4j.Logger;
import com.huawei.esdk.platform.common.config.ConfigManager;
import com.huawei.esdk.platform.common.utils.StringUtils;

public class LdapConnectionFactory
{
    public static final String CN_USERS = ConfigManager.getInstance().getValue("tpoa_cn_users");
    
    private static final Logger LOGGER = Logger.getLogger(LdapConnectionFactory.class);
    
    private static LdapConnection ldapConnection;
    
    private static String url;
    
    private static String userName;
    
    private static String account;
    
    public static String domain;
    
    private static String pwd;
    
//    private static Map<String, ADUserCredentials> userCredentialsMap = new HashMap<String, ADUserCredentials>();
    
    public synchronized static LdapConnection getConnection()
        throws Exception
    {
        if (null == ldapConnection || !ldapConnection.isConnected())
        {
            LOGGER.error("Connection failed, need to reconnection");
            initConnection(url, userName, pwd);
        }
        
        return ldapConnection;
    }
    
    public static void initConnection(String url, String userName, String pwd)
        throws Exception
    {
        
        if (null == url || null == userName || null == pwd)
        {
            return;
        }
        
        if (!checkEmail(userName))
        {
            String errInfo = "AD Device userName incorrect, should be an email addresss";
            LOGGER.error(errInfo);
            throw new Exception(errInfo);
        }
        
        LdapConnectionFactory.url = url;
        LdapConnectionFactory.userName = userName;
        LdapConnectionFactory.pwd = pwd;
        
        String[] res = splitChar(userName, "@");
        LdapConnectionFactory.domain = res[1];
        LdapConnectionFactory.account = res[0];
        
        URL serverUrl = new URL(url);
        
        LdapConnectionConfig config = new LdapConnectionConfig();
        config.setLdapHost(serverUrl.getHost());
        config.setLdapPort(serverUrl.getPort());
        
        config.setName("CN=" + LdapConnectionFactory.account + "," + CN_USERS + ","
            + LdapConnectionFactory.getDC(LdapConnectionFactory.domain));
        
        config.setUseSsl(true);
        config.setSslProtocol("SSLv3");
        config.setCredentials(pwd);
        config.setTrustManagers(new NoVerificationTrustManager());
        PoolableLdapConnectionFactory factory = new PoolableLdapConnectionFactory(config);
        LdapConnectionPool pool = new LdapConnectionPool(factory);
        pool.setTestOnBorrow(true);
        
        ldapConnection = pool.getConnection();
        ldapConnection.bind();
        LOGGER.info("AD Verification success");
        
    }
    
//    public static SDKErrorCode verificateADUserAccess(String loginName, String userPassword)
//    {
//        SDKErrorCode response = new SDKErrorCode();
//        
//        String lastSetTime = null;
//        try
//        {
//            lastSetTime = checkPwdLastSetTime(loginName);
//        }
//        catch (Exception e)
//        {
//            LOGGER.error("AD checkPwdLastSetTime failed", e);
//            response.setErrCode(ESDKErrorCodeConstant.ERROR_CODE_DEVICE_CONN_ERROR);
//            return response;
//        }
//        
//        if (StringUtils.isEmpty(loginName) || StringUtils.isEmpty(userPassword))
//        {
//            response.setErrCode(ErrInfo.AD_APPPWD_ERRORCODE);
//            return response;
//        }
//        
//        boolean isSuccess = false;
//        String encryptedLoginName = adCredentialEncryption(loginName);
//        if (userCredentialsMap.containsKey(encryptedLoginName))
//        {
//            ADUserCredentials credential = userCredentialsMap.get(encryptedLoginName);
//            
//            if (null != lastSetTime && lastSetTime.equals(credential.getPwdLastSet())
//                && adCredentialEncryption(loginName, userPassword).equals(credential.getEncryptedCredentials()))
//            {
//                isSuccess = true;
//                response.setErrCode(0);
//            }
//        }
//        
//        if (!isSuccess)
//        {
//            boolean status = false;
//            try
//            {
//                status = checkADPwd(loginName, userPassword);
//            }
//            catch (Exception e)
//            {
//                LOGGER.warn("AD Verification failed:" + e.getMessage());
//            }
//            
//            if (status)
//            {
//                ADUserCredentials credential = new ADUserCredentials();
//                String encryptedCredential = adCredentialEncryption(loginName, userPassword);
//                credential.setEncryptedCredentials(encryptedCredential);
//                credential.setPwdLastSet(lastSetTime);
//                userCredentialsMap.put(adCredentialEncryption(loginName), credential);
//                response.setErrCode(0);
//            }
//            else
//            {
//                response.setErrCode(ErrInfo.AD_APPPWD_ERRORCODE);
//            }
//        }
//        
//        return response;
//    }
//    
//    private static String checkPwdLastSetTime(String loginName)
//        throws Exception
//    {
//        
//        String pwdLastSetAttrName = ConfigManager.getInstance().getValue("tpoa_ad_pwdLastSet");
//        LdapConnection ldapConnection = LdapConnectionFactory.getConnection();
//        
//        SearchRequest req = new SearchRequestImpl();
//        req.setScope(SearchScope.ONELEVEL);
//        req.addAttributes(pwdLastSetAttrName);
//        req.setTimeLimit(0);
//        req.setBase(new Dn(CN_USERS + "," + LdapConnectionFactory.getDC(LdapConnectionFactory.domain)));
//        req.setFilter("(cn=" + loginName + ")");
//        
//        SearchCursor searchCursor = ldapConnection.search(req);
//        
//        while (searchCursor.next())
//        {
//            Response response = searchCursor.get();
//            
//            if (response instanceof SearchResultEntry)
//            {
//                Entry resultEntry = ((SearchResultEntry)response).getEntry();
//                String lastSetTime = resultEntry.get(pwdLastSetAttrName).getString();
//                return lastSetTime;
//            }
//        }
//        searchCursor.close();
//        
//        return null;
//    }
    
//    public static boolean checkADPwd(String loginName, String userpwd)
//        throws Exception
//    {
//        String adName = getADLoginNameBySmtp(loginName);
//        
//        if (StringUtils.isEmpty(adName))
//        {
//            return false;
//        }
//        
//        URL serverUrl = new URL(url);
//        LdapConnectionConfig config = new LdapConnectionConfig();
//        config.setLdapHost(serverUrl.getHost());
//        config.setLdapPort(serverUrl.getPort());
//        config.setName("CN=" + adName + "," + CN_USERS + ","
//            + LdapConnectionFactory.getDC(LdapConnectionFactory.domain));
//        
//        config.setUseSsl(true);
//        config.setSslProtocol("SSLv3");
//        config.setCredentials(userpwd);
//        config.setTrustManagers(new NoVerificationTrustManager());
//        PoolableLdapConnectionFactory factory = new PoolableLdapConnectionFactory(config);
//        LdapConnectionPool pool = new LdapConnectionPool(factory);
//        pool.setTestOnBorrow(true);
//        LdapConnection connection;
//        
//        connection = pool.getConnection();
//        connection.bind();
//        
//        if (connection.isConnected())
//        {
//            LOGGER.info("AD Verification success");
//            connection.close();
//            return true;
//        }
//        
//        return false;
//    }
    
//    private static String getADLoginNameBySmtp(String smtpAddress)
//        throws Exception
//    {
//        String tpoa_ad_name = ConfigManager.getInstance().getValue("tpoa_ad_name");
//        
//        LdapConnection ldapConnection = LdapConnectionFactory.getConnection();
//        
//        SearchRequest req = new SearchRequestImpl();
//        req.setScope(SearchScope.ONELEVEL);
//        req.setTimeLimit(0);
//        
//        req.setBase(new Dn(CN_USERS + "," + LdapConnectionFactory.getDC(LdapConnectionFactory.domain)));
//        req.addAttributes(tpoa_ad_name);
//        req.setFilter("(" + ConfigManager.getInstance().getValue("tpoa_ad_proxyAddresses_SMTP") + smtpAddress + ")");
//        
//        SearchCursor searchCursor = ldapConnection.search(req);
//        
//        while (searchCursor.next())
//        {
//            Response response = searchCursor.get();
//            
//            if (response instanceof SearchResultEntry)
//            {
//                Entry resultEntry = ((SearchResultEntry)response).getEntry();
//                
//                String adName = resultEntry.get(tpoa_ad_name).getString();
//                
//                if (!StringUtils.isEmpty(adName))
//                {
//                    return adName;
//                }
//                
//            }
//        }
//        
//        searchCursor.close();
//        return "";
//    }
    
    public static void destroyConn()
    {
        if (null != ldapConnection && ldapConnection.isConnected())
        {
            try
            {
                ldapConnection.close();
            }
            catch (IOException e)
            {
                LOGGER.info("destroy AD conn failed", e);
            }
        }
    }
    
//    private static String adCredentialEncryption(String... parameters)
//    {
//        String[] params = parameters.clone();
//        StringBuffer sb = new StringBuffer();
//        for (String item : params)
//        {
//            sb.append(item);
//        }
//        return SHA256Utils.encrypt(sb.toString());
//    }
    
    private static String[] splitChar(String str, String flag)
    {
        int index = str.indexOf(flag);
        if (-1 == index)
        {
            return new String[2];
        }
        String[] res = new String[2];
        res[0] = str.substring(0, index);
        res[1] = str.substring(index + 1);
        
        return res;
    }
    
    public static String getDC(String dcStr)
    {
        if (null == dcStr)
        {
            return null;
        }
        
        if (-1 == dcStr.indexOf("."))
        {
            return "DC=" + dcStr;
        }
        
        String[] dcs = dcStr.split("\\.");
        
        StringBuffer sb = new StringBuffer("");
        for (String item : dcs)
        {
            sb.append("DC=").append(item).append(",");
        }
        
        return sb.toString().substring(0, sb.length() - 1);
    }
    
    public static boolean checkEmail(String email)
    {
        boolean flag = false;
        if (StringUtils.isNotEmpty(email) && -1 != email.indexOf("@"))
        {
            return true;
        }
        return flag;
    }
}
